<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
  </head>

  <body>
    <script>
      function* task() {
        const resp = yield fetch('http://101.132.72.36:5100/api/local');
        const result = yield resp.json();
        console.log(result);
      }

      run(task);

      function run(generatorFunc) {
        const generator = generatorFunc();
        let result = generator.next(); //启动任务（开始迭代）, 得到迭代数据
        handleResult();
        //对result进行处理
        function handleResult() {
          if (result.done) {
            return; //迭代完成，不处理
          }
          //迭代没有完成，分为两种情况
          //1. 迭代的数据是一个Promise
          //2. 迭代的数据是其他数据
          if (typeof result.value.then === 'function') {
            //1. 迭代的数据是一个Promise
            //等待Promise完成后，再进行下一次迭代
            result.value.then((data) => {
              result = generator.next(data);
              handleResult();
            });
          } else {
            //2. 迭代的数据是其他数据，直接进行下一次迭代
            result = generator.next(result.value);
            handleResult();
          }
        }
      }

      const getData = () =>
        new Promise((resolve) => setTimeout(() => resolve('data'), 1000));

      function* testG() {
        // await被编译成了yield
        const data = yield getData();
        console.log('data: ', data);
        const data2 = yield getData();
        console.log('data2: ', data2);
        return 'success';
      }

      var test = asyncToGenerator(testG);

      // 优化版本
      function asyncToGenerator(fn) {
        return function (...args) {
          const gn = fn.apply(this, ...args);
          return new Promise((resolve, reject) => {
            function step(name, arg) {
              let result;
              try {
                result = gn[name](arg);
              } catch (error) {
                reject(error);
              }
              const { value, done } = result;
              if (done) {
                resolve(value);
              } else {
                Promise.resolve(value).then(
                  (data) => {
                    step('next', data);
                  },
                  (err) => {
                    step('throw', err);
                  }
                );
              }
            }
            step('next');
          });
        };
      }

      test().then((res) => console.log(res));
    </script>
  </body>
</html>
